package com.smile.frame.workflow.flowable.demo.listener;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.ImmutableSet;
import com.smile.frame.workflow.flowable.demo.constants.BpmConstants;
import com.smile.frame.workflow.flowable.demo.constants.BpmDeleteReasonEnum;
import com.smile.frame.workflow.flowable.demo.constants.BpmTaskStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
import org.flowable.engine.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
import org.flowable.engine.delegate.event.FlowableActivityCancelledEvent;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;

/**
 * 监听 {@link Task} 的开始与完成
 */
@Component
@Slf4j
public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    public static final Set<FlowableEngineEventType> TASK_EVENTS = ImmutableSet.<FlowableEngineEventType>builder()
            .add(FlowableEngineEventType.TASK_CREATED) //任务创建时
            .add(FlowableEngineEventType.TASK_ASSIGNED)// 任务被分配时
//            .add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时，已经记录了 task 的 status 为通过，所以不需要监听了。
            .add(FlowableEngineEventType.ACTIVITY_CANCELLED) // 任务被取消时
            .build();

    public BpmTaskEventListener() {
        super(TASK_EVENTS);
    }


    @Override
    protected void taskCreated(FlowableEngineEntityEvent event) {
        log.info("任务监听，任务创建 start");
        Task task = (Task) event.getEntity();
        Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
        if (status != null) {
            log.error("[updateTaskStatusWhenCreated][taskId({}) 已经有状态({})]", task.getId(), status);
            return;
        }

        updateTaskStatus(task.getId(), BpmTaskStatusEnum.RUNNING.getStatus());
        log.info("任务监听，任务创建 end");
    }

    @Override
    protected void taskAssigned(FlowableEngineEntityEvent event) {
        log.info("任务监听，任务分配 start");
        log.info("taskAssigned 任务分配:{}", JSONUtil.toJsonStr((Task) event.getEntity()));
        log.info("任务监听，任务分配 end");
    }

    @Override
    protected void activityCancelled(FlowableActivityCancelledEvent event) {
        log.info("任务监听，活动取消 start");

        List<HistoricActivityInstance> activityList = historyService.createHistoricActivityInstanceQuery().executionId(event.getExecutionId()).list();

        if (CollUtil.isEmpty(activityList)) {
            log.error("[activityCancelled][使用 executionId({}) 查找不到对应的活动实例]", event.getExecutionId());
            return;
        }
        // 遍历处理
        activityList.forEach(activity -> {
            if (StrUtil.isEmpty(activity.getTaskId())) {
                return;
            }
            Task task = taskService.createTaskQuery().taskId(activity.getTaskId()).includeTaskLocalVariables().singleResult();
            ;
            // 1. 可能只是活动，不是任务，所以查询不到
            if (task == null) {
                log.error("[updateTaskStatusWhenCanceled][taskId({}) 任务不存在]", activity.getTaskId());
                return;
            }

            // 2. 更新 task 状态 + 原因
            Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
            if (BpmTaskStatusEnum.isEndStatus(status)) {
                log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({})，无需进行更新]", activity.getTaskId(), status);
                return;
            }
            updateTaskStatusAndReason(activity.getTaskId(), BpmTaskStatusEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_BY_SYSTEM.getReason());

        });
        log.info("任务监听，活动取消 end");
    }

    /**
     * 更新流程任务的 status 状态
     *
     * @param id     任务编号
     * @param status 状态
     */
    private void updateTaskStatus(String id, Integer status) {
        taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_STATUS, status);
    }


    /**
     * 更新流程任务的 status 状态、reason 理由
     *
     * @param id     任务编号
     * @param status 状态
     * @param reason 理由（审批通过、审批不通过的理由）
     */
    private void updateTaskStatusAndReason(String id, Integer status, String reason) {
        updateTaskStatus(id, status);
        taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_REASON, reason);
    }
}
